package io.plus.client;

import drds.common.Clock;
import io.plus.client.user_interface.ClientAioListener;
import io.plus.interactive.CloseCode;
import io.plus.interactive.Io;
import io.plus.interactive.Node;
import io.plus.interactive.ReadCompletionHandler;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

@Slf4j
public class ConnectionCompletionHandler implements CompletionHandler<Void, ConnectionCompletionVo> {

    @Override
    public void completed(Void result, ConnectionCompletionVo attachment) {
        handler(result, attachment, null);
    }

    @Override
    public void failed(Throwable throwable, ConnectionCompletionVo attachment) {
        handler(null, attachment, throwable);
    }

    private void handler(Void result, ConnectionCompletionVo attachment, Throwable throwable) {
        ClientAsynchronousSocketChannelContext clientChannelContext = attachment.getClientChannelContext();
        AsynchronousSocketChannel asynchronousSocketChannel = attachment.getAsynchronousSocketChannel();
        Client client = attachment.getClient();
        ClientConfiguration clientConfiguration = client.getClientConfiguration();
        Node serverNode = attachment.getServerNode();
        String bindIp = attachment.getBindIp();
        Integer bindPort = attachment.getBindPort();
        ClientAioListener clientAioListener = clientConfiguration.getClientAioListener();
        boolean isReconnect = attachment.isReconnect();
        boolean isConnected = false;

        try {
            if (throwable == null) {
                if (isReconnect) {
                    clientChannelContext.setAsynchronousSocketChannel(asynchronousSocketChannel);
                    clientChannelContext.handlerRunnable.setCanceled(false);
                    clientChannelContext.sendRunnable.setCanceled(false);

                    clientConfiguration.closeds.remove(clientChannelContext);
                } else {
                    clientChannelContext = new ClientAsynchronousSocketChannelContext(clientConfiguration, asynchronousSocketChannel);
                    clientChannelContext.setServerNode(serverNode);
                }

                clientChannelContext.setBindIp(bindIp);
                clientChannelContext.setBindPort(bindPort);

                clientChannelContext.getReConnectCount().set(0);
                clientChannelContext.setClosed(false);
                isConnected = true;

                attachment.setClientChannelContext(clientChannelContext);

                clientConfiguration.connecteds.add(clientChannelContext);

                ReadCompletionHandler readCompletionHandler = clientChannelContext.getReadCompletionHandler();
                ByteBuffer readByteBuffer = readCompletionHandler.getReadByteBuffer();//ByteBuffer.allocateDirect(clientChannelContext.clientConfiguration.getReadBufferSize());
                readByteBuffer.position(0);
                readByteBuffer.limit(readByteBuffer.capacity());
                asynchronousSocketChannel.read(readByteBuffer, readByteBuffer, readCompletionHandler);

                log.info("connected to {}", serverNode);
                if (isConnected && !isReconnect) {
                    clientChannelContext.channelState.setTimeFirstConnected(Clock.currentTimeMillis);
                }
            } else {
                log.error(throwable.toString(), throwable);
                if (clientChannelContext == null) {
                    ReConnectConfiguration reConnectConfiguration = clientConfiguration.getReConnectConfiguration();
                    if (reConnectConfiguration != null) {
                        clientChannelContext = new ClientAsynchronousSocketChannelContext(clientConfiguration, asynchronousSocketChannel);
                        clientChannelContext.setServerNode(serverNode);
                    }
                }

                if (!isReconnect) //不是重连，则是第一次连接
                {
                    if (clientChannelContext != null) {
                        attachment.setClientChannelContext(clientChannelContext);
                    }
                }
                boolean f = ReConnectConfiguration.put(clientChannelContext);
                if (!f) {
                    Io.close(clientChannelContext, null, "不需要重连，关闭该连接", true, false, CloseCode.CLIENT_CONNECTION_FAIL);
                }
            }
        } catch (Throwable e) {
            log.error(e.toString(), e);
        } finally {
            if (attachment.getCountDownLatch() != null) {
                attachment.getCountDownLatch().countDown();
            }


            try {
                if (clientChannelContext != null) {
                    clientChannelContext.setReconnect(isReconnect);
                    {
                        if (clientAioListener != null) {
                            clientAioListener.onAfterConnected(clientChannelContext, isConnected, isReconnect);
                        }
                    }

                    //Configuration configuration = clientChannelContext.clientConfiguration;

                }
            } catch (Throwable e1) {
                log.error(e1.toString(), e1);
            }
        }
    }
}
